package com.alien.admin.modules.security.service;

import com.alien.admin.exception.BadRequestException;
import com.alien.admin.exception.EntityNotFoundException;
import com.alien.admin.modules.security.config.bean.LoginProperties;
import com.alien.admin.modules.security.service.dto.JwtUserDto;
import com.alien.admin.modules.system.service.DataService;
import com.alien.admin.modules.system.service.RoleService;
import com.alien.admin.modules.system.service.UserService;
import com.alien.admin.modules.system.service.dto.UserDto;
import com.alien.admin.utils.StringUtils;
import lombok.RequiredArgsConstructor;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;

/**
 * @author: alien.guo
 * @date: 2020/12/24
 */
@RequiredArgsConstructor
@Service("userDetailsService")
public class UserDetailsServiceImpl implements UserDetailsService {
    private final UserService userService;
    private final DataService dataService;
    private final LoginProperties loginProperties;
    private final UserCacheClean userCacheClean;
    private final RoleService roleService;
    public void setEnableCache(boolean enableCache) {
        this.loginProperties.setCacheEnable(enableCache);
    }

    /**
     * 用户信息缓存
     *
     * @see {@link UserCacheClean}
     */
    static Map<String, JwtUserDto> userDtoCache = new ConcurrentHashMap<>();

    @Override
    public JwtUserDto loadUserByUsername(String username) {
        boolean searchDb = true;
        JwtUserDto jwtUserDto = null;
        if (loginProperties.isCacheEnable() && userDtoCache.containsKey(username)) {
            jwtUserDto = userDtoCache.get(username);
            searchDb = false;
        }
        if (searchDb) {
            UserDto user;
            try {
                user = userService.findByName(username);
            } catch (EntityNotFoundException e) {
                // SpringSecurity会自动转换UsernameNotFoundException为BadCredentialsException
                throw new UsernameNotFoundException("", e);
            }
            if (user == null) {
                throw new UsernameNotFoundException("");
            } else {
                if (!user.getEnabled()) {
                    throw new BadRequestException("账号未激活！");
                }

                String env = userCacheClean.getUserEnv(username);
                if(StringUtils.isEmpty(env)) {
                    jwtUserDto = new JwtUserDto(
                            user,
                            dataService.getDeptIds(user),
                            initGrantedAuthorities()
                    );
                } else {
                    jwtUserDto = new JwtUserDto(
                            user,
                            dataService.getDeptIds(user),
                            roleService.mapToGrantedAuthorities(user, env)
                    );
                }

                userDtoCache.put(username, jwtUserDto);
            }
        }
        return jwtUserDto;
    }

    public List<GrantedAuthority> initGrantedAuthorities() {
        List<String> permissions = new ArrayList<>(2);
        permissions.add("menu:list");
        permissions.add("env:list");

        List<GrantedAuthority> authorities = permissions.stream().map(SimpleGrantedAuthority::new)
                .collect(Collectors.toList());
        return authorities;
    }
}
